/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package webcamtracking;

import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.Player;
import javax.media.control.FrameGrabbingControl;
import javax.media.format.VideoFormat;
import javax.media.util.BufferToImage;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

/**
 *
 * @author James
 */
public class WebcamTracker {

    private JLabel rawImageLabel;
    private JLabel modImageLabel;
    private BufferedImage rawImg;
    private BufferedImage modImg;
    private BufferedImage lastFrame;
    private int edgeThreshold;
    private int colorThreshold;
    private int boxSize;
    private int boxAreaThreshold;
    private int boxEdgeThreshold;
    private int backgroundThreshold;
    private MediaLocator ml;
    private Player player;
    private boolean play;
    private boolean execute;
    private Thread t;
    private PixelFilter edgeDetect;
    private PixelFilter colorDetect;
    private PixelFilter boxAreaShader;
    private PixelFilter boxEdgeShader;
    private PixelFilter backgroundShader;
    private int RGBcolor;
    private boolean doEdgeDetect;
    private boolean doColorDetect;
    private boolean doBoxAreaShading;
    private boolean doBoxEdgeShading;
    private boolean doBackgroundShading;
    private long systemTime;
    private int frameCount;
    JFrame frame;

    public WebcamTracker() {
        play = true;
        execute = true;
        RGBcolor = 0;
        doEdgeDetect = false;
        doColorDetect = false;
        doBoxAreaShading = false;
        boxSize = 10;
        boxAreaThreshold = 0;
        systemTime = System.currentTimeMillis();
        frameCount = 0;
        try { //gets a list of devices how support the given videoformat

            ml = new MediaLocator("vfw://0");

            player = Manager.createRealizedPlayer(ml);

            player.start();

        } catch (Exception e) {
            System.out.println(e);
        }

        initComponents();
        edgeDetect = new PixelFilter();
        edgeDetect.setAction(new Action() {

            public BufferedImage filter(BufferedImage rawImage) {
                ImageProcessor ip = new ImageProcessor();
                return ip.edgeDetection(rawImage, edgeThreshold);
            }
        });

        colorDetect = new PixelFilter();
        colorDetect.setAction(new Action() {

            public BufferedImage filter(BufferedImage rawImage) {
                ImageProcessor ip = new ImageProcessor();
                return ip.colorDetection(rawImage, RGBcolor, colorThreshold);
            }
        });

        boxAreaShader = new PixelFilter();
        boxAreaShader.setAction(new Action() {

            public BufferedImage filter(BufferedImage rawImage) {
                ImageProcessor ip = new ImageProcessor();
                return ip.populateWithAreaBoxes(rawImage, boxSize, boxAreaThreshold);
            }
        });

        boxEdgeShader = new PixelFilter();
        boxEdgeShader.setAction(new Action() {

            public BufferedImage filter(BufferedImage rawImage) {
                ImageProcessor ip = new ImageProcessor();
                return ip.populateWithEdgeBoxes(rawImage, boxSize, boxEdgeThreshold);
            }
        });

        backgroundShader = new PixelFilter();
        backgroundShader.setAction(new Action() {

            public BufferedImage filter(BufferedImage rawImage) {
                ImageProcessor ip = new ImageProcessor();
                return ip.backgroundDifference(lastFrame, rawImage, backgroundThreshold);
            }
        });

    }

    private void initComponents() {

        frame = new JFrame("Webcam Tracking");
        JPanel mainPanel = new JPanel();
        mainPanel.setLayout(new GridBagLayout());
        GridBagConstraints c = new GridBagConstraints();

        final JLabel colorLabel = new JLabel();
        c.fill = GridBagConstraints.HORIZONTAL;
        c.gridx = 1;
        c.gridy = 1;
        mainPanel.add(colorLabel, c);

        rawImageLabel = new JLabel();
        c.fill = GridBagConstraints.HORIZONTAL;
        c.gridx = 0;
        c.gridy = 0;
        rawImageLabel.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseClicked(MouseEvent e) {
                Pixel p = new Pixel(rawImg.getRGB(e.getX(), e.getY()));
                String str = p.getRed() + "," + p.getGreen() + "," + p.getBlue();
                colorLabel.setText(str);
                RGBcolor = p.getRGB();
            }
        });
        mainPanel.add(rawImageLabel, c);

        modImageLabel = new JLabel();
        c.fill = GridBagConstraints.HORIZONTAL;
        c.gridx = 1;
        c.gridy = 0;
        mainPanel.add(modImageLabel, c);

        JButton playPauseButton = new JButton("Play/Pause");
        c.fill = GridBagConstraints.HORIZONTAL;
        c.gridx = 0;
        c.gridy = 1;
        playPauseButton.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                play = !play;
            }
        });
        mainPanel.add(playPauseButton, c);

        JSlider edgeThresholdSlider = new JSlider(JSlider.HORIZONTAL, 0, 100, 0);
        c.fill = GridBagConstraints.HORIZONTAL;
        c.gridx = 0;
        c.gridy = 4;
        c.gridwidth = 1;
        edgeThresholdSlider.setMajorTickSpacing(10);
        edgeThresholdSlider.setPaintTicks(true);
        edgeThresholdSlider.setPaintLabels(true);
        edgeThresholdSlider.addChangeListener(new ChangeListener() {

            public void stateChanged(ChangeEvent e) {
                JSlider source = (JSlider) e.getSource();
                edgeThreshold = source.getValue();
            }
        });
        mainPanel.add(edgeThresholdSlider, c);

        JSlider colorThresholdSlider = new JSlider(JSlider.HORIZONTAL, 0, 100, 0);
        c.fill = GridBagConstraints.HORIZONTAL;
        c.gridx = 1;
        c.gridy = 4;
        c.gridwidth = 1;
        colorThresholdSlider.setMajorTickSpacing(10);
        colorThresholdSlider.setPaintTicks(true);
        colorThresholdSlider.setPaintLabels(true);
        colorThresholdSlider.addChangeListener(new ChangeListener() {

            public void stateChanged(ChangeEvent e) {
                JSlider source = (JSlider) e.getSource();
                colorThreshold = source.getValue();
            }
        });
        colorThresholdSlider.getModel().setValue(60);
        mainPanel.add(colorThresholdSlider, c);

        JCheckBox edgeCheckBox = new JCheckBox("Edge Detection");
        //c.fill = GridBagConstraints.HORIZONTAL;
        c.gridx = 0;
        c.gridy = 3;
        edgeCheckBox.addItemListener(new ItemListener() {

            public void itemStateChanged(ItemEvent e) {
                doEdgeDetect = e.getStateChange() == ItemEvent.SELECTED;
            }
        });
        mainPanel.add(edgeCheckBox, c);

        JCheckBox colorCheckBox = new JCheckBox("Color Detection");
        //c.fill = GridBagConstraints.HORIZONTAL;
        c.gridx = 1;
        c.gridy = 3;
        colorCheckBox.addItemListener(new ItemListener() {

            public void itemStateChanged(ItemEvent e) {
                doColorDetect = e.getStateChange() == ItemEvent.SELECTED;
            }
        });
        mainPanel.add(colorCheckBox, c);

        JCheckBox boxCheckBox = new JCheckBox("Box Shade");
        //c.fill = GridBagConstraints.HORIZONTAL;
        c.gridx = 2;
        c.gridy = 3;
        boxCheckBox.addItemListener(new ItemListener() {

            public void itemStateChanged(ItemEvent e) {
                doBoxAreaShading = e.getStateChange() == ItemEvent.SELECTED;
            }
        });
        mainPanel.add(boxCheckBox, c);

        JCheckBox boxEdgeCheckBox = new JCheckBox("Box Edge Shade");
        //c.fill = GridBagConstraints.HORIZONTAL;
        c.gridx = 0;
        c.gridy = 8;
        boxEdgeCheckBox.addItemListener(new ItemListener() {

            public void itemStateChanged(ItemEvent e) {
                doBoxEdgeShading = e.getStateChange() == ItemEvent.SELECTED;
            }
        });
        mainPanel.add(boxEdgeCheckBox, c);

        JCheckBox backgroundShadeCheckBox = new JCheckBox("Background Shade");
        //c.fill = GridBagConstraints.HORIZONTAL;
        c.gridx = 1;
        c.gridy = 8;
        backgroundShadeCheckBox.addItemListener(new ItemListener() {

            public void itemStateChanged(ItemEvent e) {
                lastFrame = rawImg;
                doBackgroundShading = e.getStateChange() == ItemEvent.SELECTED;

            }
        });
        mainPanel.add(backgroundShadeCheckBox, c);

        JLabel boxSizeSliderLabel = new JLabel("Box Size");
        c.fill = GridBagConstraints.HORIZONTAL;
        c.gridx = 0;
        c.gridy = 5;
        mainPanel.add(boxSizeSliderLabel, c);

        JLabel boxAreaThresholdSliderLabel = new JLabel("Box Area Threshold");
        c.fill = GridBagConstraints.HORIZONTAL;
        c.gridx = 1;
        c.gridy = 5;
        mainPanel.add(boxAreaThresholdSliderLabel, c);

        JSlider boxSizeSlider = new JSlider(JSlider.HORIZONTAL, 10, 45, 10);
        c.fill = GridBagConstraints.HORIZONTAL;
        c.gridx = 0;
        c.gridy = 6;
        c.gridwidth = 1;
        boxSizeSlider.setMajorTickSpacing(10);
        boxSizeSlider.setPaintTicks(true);
        boxSizeSlider.setPaintLabels(true);
        boxSizeSlider.addChangeListener(new ChangeListener() {

            public void stateChanged(ChangeEvent e) {
                JSlider source = (JSlider) e.getSource();
                if (!source.getValueIsAdjusting()) {
                    boxSize = source.getValue();

                }

            }
        });
        boxSizeSlider.getModel().setValue(20);
        mainPanel.add(boxSizeSlider, c);


        JSlider boxThresholdSlider = new JSlider(JSlider.HORIZONTAL, 0, 256, 256);
        c.fill = GridBagConstraints.HORIZONTAL;
        c.gridx = 1;
        c.gridy = 6;
        c.gridwidth = 1;
        boxThresholdSlider.setMajorTickSpacing(25);
        boxThresholdSlider.setPaintTicks(true);
        boxThresholdSlider.setPaintLabels(true);
        boxThresholdSlider.addChangeListener(new ChangeListener() {

            public void stateChanged(ChangeEvent e) {
                JSlider source = (JSlider) e.getSource();
                boxAreaThreshold = source.getValue();
            }
        });
        boxThresholdSlider.setValue(256);
        mainPanel.add(boxThresholdSlider, c);

        final JLabel keyLabel = new JLabel("Key Press: ");
        c.fill = GridBagConstraints.HORIZONTAL;
        c.gridx = 0;
        c.gridy = 7;
        c.gridwidth = 1;
        mainPanel.add(keyLabel, c);

        keyLabel.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseClicked(MouseEvent e) {
                keyLabel.requestFocus();
            }
        });

        keyLabel.addKeyListener(new KeyAdapter() {

            @Override
            public void keyPressed(KeyEvent e) {
                keyLabel.setText("Key Press: " + e.getKeyCode());
            }
        });


        JSlider boxEdgeThresholdSlider = new JSlider(JSlider.HORIZONTAL, 0, 256, 256);
        c.fill = GridBagConstraints.HORIZONTAL;
        c.gridx = 0;
        c.gridy = 9;
        c.gridwidth = 1;
        boxEdgeThresholdSlider.setMajorTickSpacing(25);
        boxEdgeThresholdSlider.setPaintTicks(true);
        boxEdgeThresholdSlider.setPaintLabels(true);
        boxEdgeThresholdSlider.addChangeListener(new ChangeListener() {

            public void stateChanged(ChangeEvent e) {
                JSlider source = (JSlider) e.getSource();
                boxAreaThreshold = source.getValue();
            }
        });
        boxEdgeThresholdSlider.setValue(256);
        mainPanel.add(boxEdgeThresholdSlider, c);

        JSlider backgroundShadeThresholdSlider = new JSlider(JSlider.HORIZONTAL, 0, 100, 0);
        c.fill = GridBagConstraints.HORIZONTAL;
        c.gridx = 1;
        c.gridy = 9;
        c.gridwidth = 1;
        backgroundShadeThresholdSlider.setMajorTickSpacing(25);
        backgroundShadeThresholdSlider.setPaintTicks(true);
        backgroundShadeThresholdSlider.setPaintLabels(true);
        backgroundShadeThresholdSlider.addChangeListener(new ChangeListener() {

            public void stateChanged(ChangeEvent e) {
                JSlider source = (JSlider) e.getSource();
                backgroundThreshold = source.getValue();
            }
        });
        backgroundShadeThresholdSlider.setValue(0);
        mainPanel.add(backgroundShadeThresholdSlider, c);



        int width = 850;
        int height = 600;
        frame.add(mainPanel);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(width, height);
        frame.setVisible(true);

        t = new Thread(new Runnable() {

            public void run() {
                while (execute) {
                    while (play) {
                        capture();
                    }
                }
            }
        });
        t.start();

    }

    private void capture() {
        FrameGrabbingControl fgc = (FrameGrabbingControl) player.getControl("javax.media.control.FrameGrabbingControl");
        javax.media.Buffer buf = fgc.grabFrame();

        // Convert it to an image
        BufferToImage btoi = new BufferToImage((VideoFormat) buf.getFormat());
        Image img = btoi.createImage(buf);

        if (img != null) {
            ImageIcon ic = new ImageIcon(img);
            rawImg = new BufferedImage(ic.getIconWidth(), ic.getIconHeight(), BufferedImage.TYPE_INT_RGB);
            Graphics2D g = rawImg.createGraphics();
            g.drawImage(img, 0, 0, null);

            BufferedImage workingImage = rawImg;

            if (lastFrame == null){
                lastFrame = rawImg;
            }
                
            /*if (frameCount == 50){
            lastFrame = rawImg;
            frameCount = 0;
            }else{
            frameCount++;
            }*/

            if (doBackgroundShading) {
                workingImage = backgroundShader.filter(rawImg);
            }

            if (doColorDetect) {
                workingImage = colorDetect.filter(workingImage);
            }
            if (doEdgeDetect) {
                workingImage = edgeDetect.filter(workingImage);
            }
            
            if (doBoxEdgeShading){
                workingImage = boxEdgeShader.filter(workingImage);
            }

            if (doBoxAreaShading) {
                workingImage = boxAreaShader.filter(workingImage);
            }

            modImg = workingImage;
            displayImages();

            long timePassed = System.currentTimeMillis() - systemTime;
            float fps = (float) 1000 / (float) timePassed;
            frame.setTitle("Webcam Tracking - FPS: " + fps);


            systemTime = System.currentTimeMillis();
        }


    }

    private void displayImages() {
        ImageIcon ic = new ImageIcon(rawImg);
        rawImageLabel.setIcon(ic);
        ic = new ImageIcon(modImg);
        modImageLabel.setIcon(ic);
    }
}
